package com.jc.order.service.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.jc.order.constant.ErrorCode;
import com.jc.order.constant.OrderConst;
import com.jc.order.dto.*;
import com.jc.order.service.CargoFeeCalculateService;
import com.jc.order.service.JcInsuranceRateSettingService;
import com.jc.order.service.KjbInsuranceRateSettingService;
import com.jc.order.service.SystemDictDataService;
import com.jc.util.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

@Slf4j
@Service
public class CargoFeeCalculateServiceImpl implements CargoFeeCalculateService {

    @Resource
    private JcInsuranceRateSettingService jcInsuranceRateSettingService;
    @Autowired
    private KjbInsuranceRateSettingService kjbInsuranceRateSettingService;

    @Autowired
    private SystemDictDataService systemDictDataService;

    // 跨境最低保费 1RMB
    private static final BigDecimal CROSS_INSURANCE_MIN = new BigDecimal("1");
    // 传统险最低保费 30 RMB
    private static final BigDecimal TRADITIONAL_INSURANCE_MIN = new BigDecimal("30");


    @Override
    public BigDecimal calculateSumInsured(JcPolicyDTO dto) {
        // 基础保额计算
        BigDecimal baseSumInsured = calculateBaseSumInsured(dto);

//        BigDecimal freightAddition = BigDecimal.ZERO;
//        if ((dto instanceof InsuranceCrossDTO)) {
//            InsuranceCrossDTO crossDTO = (InsuranceCrossDTO) dto;
        // 运费附加计算
        BigDecimal freightAddition = calculateFreightAddition(dto)
                .orElse(BigDecimal.ZERO);
//        }
        BigDecimal insuranceAmount = baseSumInsured.add(freightAddition)
                .setScale(OrderConst.RESULT_SCALE, OrderConst.ROUNDING_MODE);
        dto.setInsuranceAmount(insuranceAmount);
        return insuranceAmount;
    }


    @Override
    public Result calculatePremium(JcPolicyDTO dto) {
        Result result = new Result();
        try {
            BigDecimal feeRate = determineFeeRate(dto, result);
            if (feeRate == null) {
                return result;
            }
            //计算原价保费 打折前的
            originalCalculate(dto);
            //计算实际保费 打折后的
            calculate(dto, feeRate);
            if (NumberUtil.isLessOrEqual(dto.getFee(), BigDecimal.ZERO)) {
                result.error().setMessage("投保金额" + dto.getInsuranceAmount() + "费率为千分之" + dto.getFeeRate() + ",计算后保费必须大于0，才能正常投保");
                return result;
            }
            return result.ok();
        } catch (Exception e) {
            log.error("保费计算异常", e);
            result.error().setMessage("保费计算失败，请联系管理员");
            result.setCode(ErrorCode.CALCULATION_ERROR);
            return result;
        }
    }

    // 核心费率决策方法
    private BigDecimal determineFeeRate(JcPolicyDTO dto, Result result) {
        if (StrUtil.isNotEmpty(dto.getProductCode())) {
            if (OrderConst.PRODUCT_CODE_1.equalsIgnoreCase(dto.getProductCode())) {
                return handleTraditionalInsurance(dto, result);
            } else if (OrderConst.PRODUCT_CODE_2.equalsIgnoreCase(dto.getProductCode())) {
                return handleCrossInsurance(dto, result);
            }
        } else {
//            if (dto instanceof InsuranceCrossDTO) {
//                return handleCrossInsurance((InsuranceCrossDTO) dto, result);
//            } else if (dto instanceof InsuranceTraditionalDTO) {
//                return handleTraditionalInsurance((InsuranceTraditionalDTO) dto, result);
//            }
        }

        result.error().setMessage("不支持的保险类型");
        return null;
    }

    // 处理跨境保险
    private BigDecimal handleCrossInsurance(JcPolicyDTO crossDTO, Result result) {
//        JcInsuranceRateSettingDTO settingDTO = new JcInsuranceRateSettingDTO();
        KjbInsuranceRateSettingDTO settingDTO = new KjbInsuranceRateSettingDTO();
        settingDTO.setTenId(crossDTO.getTenantId());
        settingDTO.setInsuranceType(1);
        settingDTO.setVersionType(crossDTO.getFeeVersionType());
        settingDTO.setTransportType(crossDTO.getTransportType());
        settingDTO.setDispatchType(crossDTO.getDispatchType());

        settingDTO.setShelfGuarantee(String.valueOf(crossDTO.getShelfGuarantee()));
        KjbInsuranceRateSettingDTO rateSetting = fetchRateSetting(settingDTO, result);
        if (rateSetting == null) {
            return null;
        }
        Map<String, Integer> feeThresholds = loadFeeThresholds();
        BigDecimal averageValue = calculateAverageValue(crossDTO);

        BigDecimal rate = determineCrossFeeRate(averageValue, feeThresholds, rateSetting, crossDTO);

        if (NumberUtil.isLessOrEqual(rate, BigDecimal.ZERO)) {
            result.error().setMessage("费率配置不能小于等于0");
            return null;
        }
        crossDTO.setOriginalFeeRate(rate);
        if (rateSetting.getDiscount() != null && rateSetting.getDiscount() < 100) {
            BigDecimal aRate = rate.multiply(new BigDecimal(rateSetting.getDiscount())).divide(new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_UP);
            return aRate;
        }

        return rate;
    }

    // 处理传统保险
    private BigDecimal handleTraditionalInsurance(JcPolicyDTO traditionalDTO, Result result) {
//        JcInsuranceRateSettingDTO settingDTO = new JcInsuranceRateSettingDTO();
        KjbInsuranceRateSettingDTO settingDTO = new KjbInsuranceRateSettingDTO();
        settingDTO.setTenId(traditionalDTO.getTenantId());
        settingDTO.setInsuranceType(2);
        settingDTO.setVersionType(traditionalDTO.getFeeVersionType());
        KjbInsuranceRateSettingDTO rateSetting = fetchRateSetting(settingDTO, result);
        if (rateSetting == null) {
            return null;
        }

        BigDecimal rate = traditionalDTO.getWarehouseTermsRequired() ?
                rateSetting.getWarehouseToWarehouse() :
                rateSetting.getPortToPort();


        if (NumberUtil.isLessOrEqual(rate, BigDecimal.ZERO)) {
            result.error().setMessage("费率配置不能小于等于0");
            return null;
        }
        traditionalDTO.setOriginalFeeRate(rate);
        if (rateSetting.getDiscount() != null && rateSetting.getDiscount() < 100) {
            BigDecimal aRate = rate.multiply(new BigDecimal(rateSetting.getDiscount())).divide(new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_UP);
            return aRate;
        }
        return rate;
    }

    // 公共费率查询方法
    private KjbInsuranceRateSettingDTO fetchRateSetting(KjbInsuranceRateSettingDTO setInsuranceType, Result result) {

        KjbInsuranceRateSettingDTO rateSetting = this.kjbInsuranceRateSettingService.selectInsuranceRateSetting(setInsuranceType);
        if (rateSetting == null) {
//            log.info("费率配置缺失 [租户ID:{}][类型:{}][版本:{}]", setInsuranceType.getTenId(), setInsuranceType.getInsuranceType(), setInsuranceType.getVersionType());

            log.info("费率配置缺失 [租户ID:{}][类型:{}][版本:{}][干线运输方式:{}][dispatchType:{}][上架保障:{}]",
                    setInsuranceType.getTenId(), setInsuranceType.getInsuranceType(), setInsuranceType.getVersionType(),
                    setInsuranceType.getTransportType(), setInsuranceType.getDispatchType(), setInsuranceType.getShelfGuarantee());


            result.error().setMessage("费率配置缺失，请联系管理员");
        }
        return rateSetting;
    }

    // 公共费率查询方法
    private JcInsuranceRateSettingDTO fetchRateSetting(JcInsuranceRateSettingDTO setInsuranceType, Result result) {


        JcInsuranceRateSettingDTO rateSetting = jcInsuranceRateSettingService.selectInsuranceRateSetting(setInsuranceType);
        if (rateSetting == null) {
//            log.info("费率配置缺失 [租户ID:{}][类型:{}][版本:{}]", setInsuranceType.getTenId(), setInsuranceType.getInsuranceType(), setInsuranceType.getVersionType());

            log.info("费率配置缺失 [租户ID:{}][类型:{}][版本:{}][干线运输方式:{}][dispatchType:{}][上架保障:{}]",
                    setInsuranceType.getTenId(), setInsuranceType.getInsuranceType(), setInsuranceType.getVersionType(),
                    setInsuranceType.getTransportType(), setInsuranceType.getDispatchType(), setInsuranceType.getShelfGuarantee());


            result.error().setMessage("费率配置缺失，请联系管理员");
        }
        return rateSetting;
    }

    // 加载费用阈值配置
    private Map<String, Integer> loadFeeThresholds() {
        return systemDictDataService.selectDictDataByDictType("FEE_VALUE").stream()
                .collect(Collectors.toMap(
                        data -> data.getLabel().toLowerCase(),
                        data -> Integer.parseInt(data.getValue())
                ));
    }

    // 计算平均货值
    private BigDecimal calculateAverageValue(JcPolicyDTO dto) {
        return dto.getGoodsValueAmount()
                .multiply(dto.getExchangeRate())
                .divide(dto.getWeightPackaged(), 4, RoundingMode.HALF_UP)
                .setScale(2, RoundingMode.HALF_UP);
    }

    // 确定跨境费率等级
    private BigDecimal determineCrossFeeRate(BigDecimal averageValue, Map<String, Integer> thresholds,
                                             KjbInsuranceRateSettingDTO rateSetting, JcPolicyDTO dto) {
        int lower = thresholds.getOrDefault("lower", 0);
        int higher = thresholds.getOrDefault("higher", Integer.MAX_VALUE);
        double value = averageValue.doubleValue();
        dto.setValueDifferentiation("higher");
        if (value < lower) {
            dto.setValueDifferentiation("lower");
            return rateSetting.getFeeLevelOne();
        } else if (value < higher) {
            return rateSetting.getFeeLevelTwo();
        } else {
            return rateSetting.getFeeLevelThree();
        }
    }


    /**
     * 计算保费和费率
     *
     * @param dto
     * @param totalRate
     */
    protected void calculate(JcPolicyDTO dto, BigDecimal totalRate) {
        BigDecimal rate = totalRate.divide(new BigDecimal(1000), 6, BigDecimal.ROUND_HALF_UP);
        BigDecimal fee = dto.getInsuranceAmount().multiply(rate).setScale(4, BigDecimal.ROUND_HALF_UP);
        BigDecimal rmbPremium = fee.multiply(dto.getExchangeRate()).setScale(2, BigDecimal.ROUND_HALF_UP);
        dto.setFeeRate(totalRate);
        log.info("保费，原币种保费 {}x{}={}，RMB保费 {}x{}={}",dto.getInsuranceAmount(),rate,fee,fee,dto.getExchangeRate(),rmbPremium);
        if (OrderConst.PRODUCT_CODE_1.equalsIgnoreCase(dto.getProductCode()) && NumberUtil.isLessOrEqual(rmbPremium, TRADITIONAL_INSURANCE_MIN)) {
            log.info("传统货运---- 保费小于等于最低保费 rmbPremium：{},最低保费：{}",rmbPremium,TRADITIONAL_INSURANCE_MIN);
            //反算原保费
            BigDecimal premium= TRADITIONAL_INSURANCE_MIN.divide(dto.getExchangeRate(),4, BigDecimal.ROUND_HALF_UP);
            dto.setPremium(premium);
            dto.setFee(TRADITIONAL_INSURANCE_MIN);
            dto.setRmbPremium(TRADITIONAL_INSURANCE_MIN);
        } else if (OrderConst.PRODUCT_CODE_2.equalsIgnoreCase(dto.getProductCode()) && NumberUtil.isLessOrEqual(rmbPremium, CROSS_INSURANCE_MIN)) {
            log.info("跨境大货---- 保费小于等于最低保费 rmbPremium：{},最低保费：{}",rmbPremium,CROSS_INSURANCE_MIN);
            //反算原保费
            BigDecimal premium= CROSS_INSURANCE_MIN.divide(dto.getExchangeRate(),4, BigDecimal.ROUND_HALF_UP);
            dto.setPremium(premium);
            dto.setFee(CROSS_INSURANCE_MIN);
            dto.setRmbPremium(CROSS_INSURANCE_MIN);
        } else {
            dto.setPremium(fee);
            dto.setFee(rmbPremium);
            dto.setRmbPremium(rmbPremium);
        }
    }


    protected void originalCalculate(JcPolicyDTO dto) {
        BigDecimal rate = dto.getOriginalFeeRate().divide(new BigDecimal(1000), 6, BigDecimal.ROUND_HALF_UP);
        BigDecimal fee = dto.getInsuranceAmount().multiply(rate).setScale(4, BigDecimal.ROUND_HALF_UP);
        dto.setOriginalFee(fee);
    }

    /**
     * 计算基础保额 = 货值 × 加成比例 ÷ 100 × 汇率
     */
    protected BigDecimal calculateBaseSumInsured(JcPolicyDTO dto) {

        return Optional.ofNullable(dto.getGoodsValueAmount()).filter(value -> NumberUtil.isGreater(value, BigDecimal.ZERO))
                .orElseThrow(() -> new IllegalArgumentException("货值不能为空"))
                .multiply(getAppendRatio(dto))
                .divide(OrderConst.HUNDRED, OrderConst.CALCULATION_SCALE, OrderConst.ROUNDING_MODE)
//                .multiply(getExchangeRate(dto))
                .setScale(OrderConst.RESULT_SCALE, OrderConst.ROUNDING_MODE);
    }

    /**
     * 获取加成比例（带默认值）
     */
    protected BigDecimal getAppendRatio(JcPolicyDTO dto) {
        return Optional.ofNullable(dto.getAppendPercent())
                .orElse(OrderConst.DEFAULT_RATIO);
    }

    /**
     * 获取汇率（带校验）
     */
    protected BigDecimal getExchangeRate(JcPolicyDTO dto) {
        return Optional.ofNullable(dto.getExchangeRate())
                .filter(rate -> rate.compareTo(BigDecimal.ZERO) > 0)
                .orElseThrow(() -> new IllegalArgumentException("无效的汇率"));
    }


    /**
     * 计算运费附加金额
     */
    protected Optional<BigDecimal> calculateFreightAddition(JcPolicyDTO dto) {
        return Optional.of(dto)
                .filter(this::isFreightAdditionRequired)
                .map(this::convertFreightToBaseCurrency);
    }

    /**
     * 判断是否需要计算运费附加
     */
    protected boolean isFreightAdditionRequired(JcPolicyDTO dto) {
        return dto.getInsuranceConfirmType() == OrderConst.INSURANCE_CONFIRM_TYPE_2
                && dto.getDeliveryAmount() != null
                && dto.getDeliveryExchangeRate() != null;
    }

    /**
     * 运费转换：运费金额 × 运费汇率 ÷ 货值汇率
     */
    protected BigDecimal convertFreightToBaseCurrency(JcPolicyDTO dto) {
        BigDecimal freightCNY = dto.getDeliveryAmount()
                .multiply(dto.getDeliveryExchangeRate())
                .setScale(OrderConst.CALCULATION_SCALE, OrderConst.ROUNDING_MODE);

        return freightCNY.divide(dto.getExchangeRate(), OrderConst.RESULT_SCALE, OrderConst.ROUNDING_MODE);
    }


}
